package com.github.caijh.mall.category.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.caijh.commons.util.Strings;
import com.github.caijh.framework.util.TreeNodes;
import com.github.caijh.mall.category.dao.CategoryMapper;
import com.github.caijh.mall.category.model.Category;
import com.github.caijh.mall.category.request.CategoryReqBody;
import com.github.caijh.mall.category.request.CategorySearchReqBody;
import com.github.caijh.mall.category.service.CategoryService;
import com.github.caijh.mall.category.vo.CategoryTreeVo;
import com.github.caijh.mall.exception.CrmebException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    @Resource
    private CategoryMapper categoryMapper;


    /**
     * 分类页.
     *
     * @param reqBody 请求参数
     * @return Page of Category
     */
    @Override
    public IPage<Category> findPage(CategorySearchReqBody reqBody) {
        Category category = new Category();
        BeanUtils.copyProperties(reqBody, category);

        LambdaQueryWrapper<Category> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(null != category.getPid(), Category::getPid, category.getPid());
        lambdaQueryWrapper.eq(null != category.getType(), Category::getType, category.getType());
        lambdaQueryWrapper.eq(null != category.getStatus(), Category::getStatus, category.getStatus());
        lambdaQueryWrapper.like(null != category.getName(), Category::getName, category.getName());
        lambdaQueryWrapper.orderByDesc(Category::getSort).orderByDesc(Category::getId);
        IPage<Category> page = new Page<>(reqBody.getPage(), reqBody.getLimit());
        return this.page(page, lambdaQueryWrapper);
    }

    /**
     * 通过id集合获取列表
     *
     * @param idList id集合
     * @return {@code List<Category>}
     */
    @Override
    public List<Category> getByIds(List<Integer> idList) {
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(Category::getId, idList);
        return categoryMapper.selectList(lambdaQueryWrapper);
    }

    /**
     * 通过id集合获取列表 id => name
     *
     * @param cateIdList id集合
     * @return {@code HashMap<Integer, String>}
     */
    @Override
    public HashMap<Integer, String> getListInId(List<Integer> cateIdList) {
        HashMap<Integer, String> map = new HashMap<>();
        List<Category> list = getByIds(cateIdList);
        for (Category category : list) {
            map.put(category.getId(), category.getName());
        }

        return map;
    }

    /**
     * 查询id和url是否存在
     *
     * @return Boolean
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    @Override
    public boolean checkAuth(List<Integer> pathIdList, String uri) {
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(Category::getId, pathIdList).eq(Category::getUrl, uri);
        List<Category> categories = categoryMapper.selectList(lambdaQueryWrapper);
        return com.github.caijh.commons.util.Collections.isNotEmpty(categories);
    }

    /**
     * 修改
     *
     * @param request CategoryRequest
     * @param id      Integer
     * @return bool
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    @Override
    public boolean update(CategoryReqBody request, Integer id) {
        try {
            //修改分类信息
            Category category = new Category();
            BeanUtils.copyProperties(request, category);
            category.setId(id);
            category.setPath(getPathByPId(category.getPid()));

            updateById(category);

            //如状态为关闭，那么所以子集的状态都关闭
            if (Boolean.FALSE.equals(request.getStatus())) {
                updateStatusByPid(id, false);
            } else {
                //如是开启，则父类的状态为开启
                updatePidStatusById(id);
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 开启父级状态
     *
     * @param id Integer
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    private void updatePidStatusById(Integer id) {
        Category category = getById(id);
        List<Integer> categoryIdList = Strings.toList(category.getPath(), "/", Integer::parseInt);
        categoryIdList.removeIf(i -> i.equals(0));
        ArrayList<Category> categoryArrayList = new ArrayList<>();
        if (categoryIdList.isEmpty()) {
            return;
        }
        for (Integer categoryId : categoryIdList) {
            Category categoryVo = new Category();
            categoryVo.setId(categoryId);
            categoryVo.setStatus(true);
            categoryArrayList.add(categoryVo);
        }
        updateBatchById(categoryArrayList);
    }

    /**
     * 获取分类下子类的数量
     *
     * @param pid Integer
     * @return bool
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    private int getChildCountByPid(Integer pid) {
        //查看是否有子类
        QueryWrapper<Category> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.like("path", "/" + pid + "/");
        return categoryMapper.selectCount(objectQueryWrapper);
    }

    /**
     * 修改分类以及子类的状态
     *
     * @param pid    类id
     * @param status 状态
     */
    private void updateStatusByPid(Integer pid, boolean status) {
        //查看是否有子类
        Category category = new Category();
        category.setStatus(status);

        QueryWrapper<Category> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.like("path", "/" + pid + "/");
        categoryMapper.update(category, objectQueryWrapper);
    }

    @Override
    public String getPathByPId(Integer pid) {
        Category category = getById(pid);
        if (null != category) {
            return category.getPath() + pid + "/";
        }
        return null;
    }

    @Override
    public List<CategoryTreeVo> getTree(Integer type, Integer status, String name) {
        return getTree(type, status, name, null);
    }

    /**
     * 带权限的属性结构
     *
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    @Override
    public List<CategoryTreeVo> getTree(Integer type, Integer status, List<Integer> categoryIdList) {
        return getTree(type, status, null, categoryIdList);
    }

    private List<CategoryTreeVo> getTree(Integer type, Integer status, String name, List<Integer> categoryIdList) {
        LambdaQueryWrapper<Category> wrapper = Wrappers.<Category>lambdaQuery()
                                                       .eq(Category::getType, type)
                                                       .in(null != categoryIdList && !categoryIdList.isEmpty(), Category::getId, categoryIdList)
                                                       .eq(status >= 0, Category::getStatus, status)
                                                       .like(StringUtils.isNotBlank(name), Category::getName, name)
                                                       .orderByDesc(Category::getSort).orderByAsc(Category::getId);
        List<Category> categories = this.list(wrapper);

        if (categories == null || categories.isEmpty()) {
            return Collections.emptyList();
        }

        if (StringUtils.isNotBlank(name)) { // find parents
            Set<Category> searchCategory = new HashSet<>();
            for (Category category : categories) {
                if (category.getPath() != null) {
                    List<String> ids =
                            Arrays.stream(category.getPath().split("/")).filter(StringUtils::isNotBlank).collect(Collectors.toList());
                    searchCategory.addAll(categoryMapper.selectBatchIds(ids));
                }
            }
            categories.addAll(searchCategory);
        }

        List<CategoryTreeVo> categoryVos = categories.stream()
                                                     .map(e -> {
                                                         CategoryTreeVo vo = new CategoryTreeVo();
                                                         BeanUtils.copyProperties(e, vo);
                                                         return vo;
                                                     }).collect(Collectors.toList());

        return new TreeNodes<>(categoryVos).asTree();
    }

    /**
     * 删除分类表
     *
     * @param id Integer
     * @return bool
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    @Override
    public int delete(Integer id) {
        //查看是否有子类, 物理删除
        if (getChildCountByPid(id) > 0) {
            throw new CrmebException("当前分类下有子类，请先删除子类！");
        }

        return categoryMapper.deleteById(id);
    }

    /**
     * 获取分类下子类
     *
     * @param pid 上一类id
     * @return {@code List<Category>}
     */
    @Override
    public List<Category> getChildVoListByPid(Integer pid) {
        //查看是否有子类
        QueryWrapper<Category> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("status", 1);
        objectQueryWrapper.like("path", "/" + pid + "/");
        return categoryMapper.selectList(objectQueryWrapper);
    }

    /**
     * 检测分类名称是否存在
     *
     * @param name String 分类名
     * @param type int 类型
     * @return int
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    @Override
    public int checkName(String name, Integer type) {
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Category::getName, name)
                          .eq(Category::getType, type);
        return categoryMapper.selectCount(lambdaQueryWrapper);
    }

    /**
     * 检测url是否存在
     *
     * @param uri String url
     * @return int
     * @author Mr.Zhang
     * @since 2020-04-16
     */
    @Override
    public boolean checkUrl(String uri) {
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Category::getUrl, uri);
        return categoryMapper.selectCount(lambdaQueryWrapper) > 0;
    }

    @Override
    public boolean updateStatus(Integer id) {
        Category category = getById(id);
        category.setStatus(!category.getStatus());
        return updateById(category);
    }

}

